#pragma once

#include <iostream>
#include <vector>
#include <pthread.h>

#include "Sem.hpp"
#include "Mutex.hpp"

namespace RingBufferModule
{
    using namespace SemModule;
    using namespace LockModule;

    // RingQueue
    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap)
        :_ring(cap),
        _cap(cap),
        _p_step(0),
        _c_step(0),
        _datasem(0),
        _spacesem(cap)
        {}

        //生产
        void Equeue(const T &in)
        {
            _spacesem.P();  //如果空间为0进行阻塞，大于0进行减一并执行下面操作

            //进行生产
            {   
            LockGuard _lock(_p_lock); //加锁
            _ring[_p_step++] = in;
            _p_step %= _cap;
            }

            _datasem.V();   //数据数目加一
        }

        void Pop(T *out)
        {
            _datasem.P();    //如果空间为0进行阻塞，大于0进行减一并执行下面操作

            //进行消费            
            {
            LockGuard _lock(_c_lock);   //加锁
            *out = _ring[_c_step++];
            _c_step %= _cap;
            }

            _spacesem.V(); //空间数目加一

        }


        ~RingBuffer()
        {}

    private:
        std::vector<T> _ring; // 环， 临界资源
        int _cap;             // 总容量
        int _p_step;          // 生产者位置
        int _c_step;          // 消费位置

        Sem _datasem;         // 数据信号量
        Sem _spacesem;        // 空间信号量

        Mutex _p_lock;         //生产者锁
        Mutex _c_lock;          //消费者锁
    };
}